## Construction of Hadamard codes

from PyM import *


def hadamard_matrix_recursive(n):
    if n==0: return matrix([[1]])
    if n > 0: 
        H = hadamard_matrix_recursive(n-1)
        k = nrows(H)
        H1 = matrix(Z_,k,k)
        for i in range(k):
            for j in range(k):
                H1[i,j] = - (H[i,j])
        return stack(splice(H,H), splice(H,H1))

def paley_matrix(F):
    if characteristic(F)==2:
        return "paley_matrix error: the characteristic of F must not be 2"
    q = cardinal(F)
    def x(j): return element(j,F)
    def chi(a): return legendre(a,F)
    return matrix([[chi(x(i)-x(j)) for j in range(q)] for i in range(q)])

def conference_matrix(K):
    q = cardinal(K)
    e = ((q-1)//2)%2
    if e==1: e=-1
    else: e=1
    S = paley_matrix(K)
    u = matrix(q*[1])
    x = splice(matrix([0]),u)
    X = splice(transpose(e*u),S)
    return stack(x,X)

def hadamard_matrix_finite_field(K):
    q = cardinal(K)
    e = ((q-1)//2)%2
    #e = (-1)**e
    I = I_(q+1,Z_); Im=-I_(q+1,Z_)
    C = conference_matrix(K)
    if e==0:
        return stack(splice(I+C,Im+C),splice(Im+C,Im-C))
    return hadamard_matrix_paley(K)

def hadamard_code(X):
    if isinstance(X,int):
        X = hadamard_matrix_recursive(X)
    elif isinstance(X,Matrix_type):
        pass
    else: 
        X = hadamard_matrix_finite_field(X)
    
    X1 = matrix(nrows(X),ncols(X))
    for i in range(nrows(X)):
        X1[:,i] = -X[:,i]
    C = stack(X,X1)
    for i in range(nrows(C)):
        for j in range(ncols(C)):
            if C[i,j]==-1:
                C[i,j] = 0
    return C

    
H1 = hadamard_code(2)

show(H1)

H2 = hadamard_code(Zn(7))

show(H2)

show(hadamard_code(hadamard_matrix(3)))
